package com.opennetexam.manager.bussinessservice;

import com.github.pagehelper.PageHelper;
import com.opennetexam.manager.common.*;
import com.opennetexam.manager.mapper.*;
import com.opennetexam.manager.databasemodel.*;
import com.opennetexam.manager.databasemodel.ExamRoom;
import com.opennetexam.manager.databasemodel.ExamScenes;
import com.opennetexam.manager.databasemodel.ExamSubject;
import com.opennetexam.manager.databasemodel.Examinee;
import com.opennetexam.manager.databasemodel.ExamineeArrange;
import com.opennetexam.manager.dto.*;
import com.opennetexam.manager.enums.*;
import com.opennetexam.manager.service.ExamSubjectService;
import com.opennetexam.manager.utils.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author 奶茶
 * Created on 2017/11/13.
 */
@Service("examPlanInfoService")
@Transactional(rollbackFor = Exception.class)
public class ExamPlanInfoService {

    private static Logger logger = Logger.getLogger(ExamPlanInfoService.class);

    @Autowired
    private ExamineeArrangeMapper examineeArrangeMapper;
    @Autowired
    private ExamScenesMapper examScenesMapper;
    @Autowired
    private ExamRoomMapper examRoomMapper;
    @Autowired
    private ExamSubjectMapper examSubjectMapper;
    @Autowired
    private ExamPlanInfoMapper examPlanInfoMapper;
    @Autowired
    private ExamPaperMapper examPaperMapper;
    @Autowired
    private ExamineeMapper examineeMapper;
    @Autowired
    private ExamMoniterMapper examMoniterMapper;
    @Autowired
    private ExamPaperItemMapper examPaperItemMapper;
    @Autowired
    private ExamingMoniterLogMapper examingMoniterLogMapper;
    @Autowired
    private ExamineeExamPaperMapper examineeExamPaperMapper;
    @Autowired
    private ExamineeExamPaperItemMapper examineeExamPaperItemMapper;
    @Autowired
    private ExamSubjectService subjectService;


    @Value("${ExamSiteURL}")
    private String examSiteURL;

    /**
     * 保存管理端主动拍照信息
     * @param examPlanID
     * @param examinerID
     * @param examinerArrangeID
     */
    public OperationResult saveTakePhotoMessage(AdminInfo adminInfo,String examPlanID,String examinerID,String examinerArrangeID){
        int i = 0;
        String cacheKey = CacheKey.getTakePhotoMessageKey(examPlanID,examinerID,examinerArrangeID);
        ExamPlanInfo examPlanInfo = examPlanInfoMapper.getExamPlanInfo(adminInfo.getAppID(), examPlanID);
        if(examPlanInfo.getDeploymentMode().equals(DeploymentMode.WAN_Deployment.getPrefix())){
            RedisUtil.setValue(cacheKey,examinerArrangeID,60);
            ++i;
        }
        return i > 0 ? new OperationResult(OperationResultType.Success) : new OperationResult(OperationResultType.Error);
    }

    /**
     * 获取管理端主动拍照信息
     * @param adminInfo
     * @param examPlanID
     * @param examinerID
     * @param examinerArrangeID
     * @return
     */
    public OperationResult getTakePhotoMessage(AdminInfo adminInfo,String examPlanID,String examinerID,String examinerArrangeID){
        int i = 0;
        String cacheKey = CacheKey.getTakePhotoMessageKey(examPlanID,examinerID,examinerArrangeID);
        ExamPlanInfo examPlanInfo = examPlanInfoMapper.getExamPlanInfo(adminInfo.getAppID(), examPlanID);
        if(examPlanInfo.getDeploymentMode().equals(DeploymentMode.WAN_Deployment.getPrefix())){
            if(!StringUtils.isEmpty(RedisUtil.getValue(cacheKey))){
                ++i;
            };
        }
        return i > 0 ? new OperationResult(OperationResultType.Success) : new OperationResult(OperationResultType.Error);
    }

    /**
     * 考试计划列表
     * @param appId
     * @param siteId
     * @param planType
     * @return
     */
    public List<ExamPlanViewModel> getExamPlanList(String appId, String siteId, Short planType,String examPlanName) {
        List<ExamPlanViewModel> examPlanViewModelList = examineeArrangeMapper.findExamPlanViewModelBySomeWhere(appId, siteId, planType,examPlanName);

        if(examPlanViewModelList != null && !examPlanViewModelList.isEmpty()){
            for (int i=0;i<examPlanViewModelList.size();i++){
                if(DateUtil.convertStringToDate(examPlanViewModelList.get(i).getEndTime()).getTime() < System.currentTimeMillis()){
                    examPlanViewModelList.get(i).setEnd(true);
                }else{
                    examPlanViewModelList.get(i).setEnd(false);
                }
                examPlanViewModelList.get(i).setExamCount(examPlanViewModelList.get(i).getExamSubjectCount());
                examPlanViewModelList.get(i).setGeneratedCount(subjectService.getSubjectCountBYStatus(examPlanViewModelList.get(i).getBatchId(),SubjectPaperStatus.DownloadCompleteAndPaperGenerate.getPrefix()));
            }
        }
        return examPlanViewModelList;
    }

    /**
     * 获取场次的下拉列表
     * @param appId
     * @param planId
     * @param roomId
     * @param subjectId
     * @return
     */
    public List<ExamScenes> examSceneList(String appId, String planId, String roomId, String subjectId){
        return examScenesMapper.findExamScenesListBySomeWhere(appId, planId, roomId, subjectId);
    }

    /**
     * 获取考场的下拉列表
     * @param appId
     * @param planId
     * @param sceneId
     * @param subjectId
     * @return
     */
    public List<ExamRoom> examRoomList(String appId, String planId, String sceneId, String subjectId){
        return examRoomMapper.findExamRoomListBySomeWhere(appId, planId, sceneId, subjectId);
    }

    /**
     * 获取科目的下拉列表
     * @param planId
     * @return
     */
    public List<ExamSubject> examSubjectList(String planId){
        return examSubjectMapper.findExamSubjectListBySomeWhere(planId);
    }

    /**
     * 考试计划详细列表
     * @param planId 考试计划ID
     * @param roomId 考场ID
     * @param sceneId 场次ID
     * @param subjectId 科目ID
     * @param appId 主办方ID
     * @param siteId 考点ID
     * @return
     */
    public List<ExamPlanDetailViewModel> selectbyExamSubject(String planId, String roomId, String sceneId, String subjectId, String appId, String siteId){
        List<ExamPlanDetailViewModel> examPlanDetailViewModelList = examPlanInfoMapper.findExamPlanDetailViewModelListBySomeWhere(planId, roomId, sceneId, subjectId, appId, siteId);
        for (ExamPlanDetailViewModel detailViewModel:examPlanDetailViewModelList){
            int millTimeLimits = detailViewModel.getTimeLimits() * 60 * 1000;
            long time = DateUtil.convertStringToDate(detailViewModel.getSceneBeginTime()).getTime();
            detailViewModel.setSceneEndTime(DateUtil.convertMillisecondToDateString(millTimeLimits+time));
        }
        return examPlanDetailViewModelList;
    }


    /**
     * 获取批次列表
     * @param adminInfo
     * @return
     */
    public List<Map> getBatchList(ExamAdminInfoDTO adminInfo){
        List<Map> maps = new ArrayList<>();
        //查询数据库中所有批次
        List<ExamPlanInfo> allExamPlan = examPlanInfoMapper.findAllExamPlan(adminInfo.getAppID());
        //获取当前考点下的所有批次
        String requestUrl = examSiteURL + "examplan/getbatches?exampointCode=" + adminInfo.getExamSiteID();
        String result = HttpRequestUtils.sendGet(requestUrl, null);
        if(!StringUtils.isEmpty(result)){
            maps = GsonUtil.fromJsonToList(result, Map.class);
        }

        if(allExamPlan != null && !allExamPlan.isEmpty() && !maps.isEmpty()){
            for (Map map:maps) {
                map.put("successCount",0);
                for (ExamPlanInfo examPlanInfo:allExamPlan) {
                    String examPlanID = map.get("batchId").toString();
                    boolean match = allExamPlan.parallelStream().anyMatch(planInfo -> planInfo.getExamPlanInfoID().equals(examPlanID));
                    if(match){
                        List<Map<String, Object>> examPlanSubject = examPlanInfoMapper.findExamPlanSubject(examPlanID);
                        examPlanSubject.forEach(map1 -> {
                            if(map1.get("subjectPaperStatus").equals(2)){
                                map.put("successCount",map1.get("count"));
                            }
                            int allSubjectCount = (map.get("allSubjectCount") == null ? 0 : Integer.valueOf(map.get("allSubjectCount").toString())) + Integer.valueOf(map1.get("count").toString());
                            map.put("allSubjectCount",allSubjectCount);
                        });
                        map.put("sysState",ExamPlanSysState.getName(examPlanInfo.getSysState()));
                        break;
                    }else{
                        map.put("sysState",ExamPlanSysState.UNDownload.getDisplay());
                        map.put("successCount",0);
                        map.put("allSubjectCount",0);
                    }
                }
            }
        }else if(allExamPlan != null && allExamPlan.isEmpty() && !maps.isEmpty()){
            maps.forEach(map -> {
                map.put("sysState",ExamPlanSysState.UNDownload.getDisplay());
                map.put("successCount",0);
                map.put("allSubjectCount",0);
            });
        }
        return maps;
    }

    /**
     * 查询所有考试计划 SysState为 1：下载中的数据
     * @return
     */
    public Boolean findAllExamPlanSysState(){
        //查询所有计划 SysState为下载中的数据
        return examPlanInfoMapper.findAllExamPlanSysState() > 0;
    }

    /**
     * 查询当前计划下所有考试科目
     * @param examPlanID
     * @return
     */
    public PageBean<ExamSubject> findAllExamSubjectByExamPlanID(String examPlanID, Integer currentPage, Integer pageSize){
        PageHelper.startPage(currentPage,pageSize);
        List<ExamSubject> allExamSubjectByExamPlanID = examSubjectMapper.findAllExamSubjectByExamPlanID(examPlanID);
        PageBean<ExamSubject> pageBean = new PageBean<ExamSubject>(currentPage, pageSize,examSubjectMapper.findAllExamSubjectCount(examPlanID));
        pageBean.setItems(allExamSubjectByExamPlanID);
        return pageBean;
    }

    //private static int corePoolSize = Runtime.getRuntime().availableProcessors();
    //
    //private static ThreadPoolExecutor executor  = new ThreadPoolExecutor(corePoolSize, corePoolSize + 1, 1, TimeUnit.SECONDS,
    //        new LinkedBlockingQueue<Runnable>(),
    //        new ThreadFactory() {
    //            @Override
    //            public Thread newThread(Runnable r) {
    //                return new Thread(r,"ThreadPool_LoadExamPlan");
    //            }
    //        });


    /**
     *
     * @param examPlanID
     * @return
     */
    public List<Map<String,Object>> findExamPlanSubjectCount(String examPlanID){
        return examSubjectMapper.findExamPlanSubjectCount(examPlanID);
    }

    /**
     * 数据处理列表
     * @param appId 主办方编号
     * @param siteId
     * @param planType 考试计划类别，正式0，测试1
     * @return 已结束的考试计划列表
     */
    public List<ExamPlanInfo> processPlanList(String appId, String siteId, Short planType){
        return examPlanInfoMapper.findExamPlanInfoLists(planType, appId, siteId);
    }

    /**
     * 删除考试计划相关数据
     *
     * @param admin 登录用户
     * @param planId 计划标识
     * @return
     */
    @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
    public OperationResult removePlanInfo(AdminInfo admin, String planId) {
        //项目根路径
        String rootPath = ExamSitePath.rootPath;
        ExamPlanInfo examPlanInfo = examPlanInfoMapper.findExamPlanInfoFirst(planId);
        if (examPlanInfo == null) {
            return new OperationResult(OperationResultType.Warning, "不存在的考试计划！");
        }

        String appID = examPlanInfo.getAppID();
        String examPlanInfoID = examPlanInfo.getExamPlanInfoID();
        List<ExamineeArrange> arrangesInfos = examineeArrangeMapper.findExamineeArrangesWhere(examPlanInfoID, appID);

        // 删除监考日志
        if (arrangesInfos == null || arrangesInfos.isEmpty()) {
            return new OperationResult(OperationResultType.Warning, "不存在的考试计划！");
        }
        examingMoniterLogMapper.deleteExamingMoniterLogByEAIds(examPlanInfoID, appID);

        //删除监考信息
        String examSiteID = admin.getExamSiteID();
        String folder = String.format("%s/files/result/%s/%s/%s/", rootPath, appID, examSiteID, planId);
        FileUtil.deleteDirectory(folder);

        //删除考试过程监控
        examMoniterMapper.delExamMoniterByPlanId(planId);

        //删除考生试卷与试题
        List<ExamineeExamPaper> examineeExamPaperList = examineeExamPaperMapper.findExamineeExamPaperByPlanId(planId);

        for (ExamineeExamPaper item : examineeExamPaperList) {
            String filePath = String.format("%s/%s/%s/%s/%s.json", ExamSitePath.ExamineePaperPath, item.getAppID(), item.getExamPlanInfoID(), item.getExamSubjectID(), item.getExamPaperInfoID());
            FileUtil.deleteFile(filePath);
        }

        examineeExamPaperItemMapper.delExamineeExamPaperItemByPageInfoIds(planId);
        examineeExamPaperMapper.delExamineeExamPaperByPlanId(planId);


        // 删除考试试卷与试题
        examPaperItemMapper.delExamPaperItemByPagerIds(planId);
        examPaperMapper.delExamPaperByPlanId(planId);

        //删除考生信息
        examineeMapper.delExamineeByPlanId(planId);

        //删除场次信息
        examScenesMapper.delExamScenesByScenesIds(appID, planId);
        //删除科目信息
        examSubjectMapper.delExamSubjectBySubjectIds(appID, planId);
        // 删除考生编排
        examineeArrangeMapper.delExamineeArrangesWhere(examPlanInfoID, appID);

        //删除计划信息
        examPlanInfoMapper.delExamPlanInfoByPlanId(planId);
        return new OperationResult(OperationResultType.Success);
    }

    /**
     * 获取所有已开始且已成功加载的批次信息
     * @return
     */
    public List<ExamPlanInfo> findAllStartExamPlanInfo(){
        return examPlanInfoMapper.findAllStartExamPlanInfo();
    }

    /**
     * 查询考试计划表
     * @param examPlanInfoID
     * @return
     */
    public ExamPlanInfo findExamPlanInfoById(String examPlanInfoID) {
        return examPlanInfoMapper.findExamPlanInfoFirst(examPlanInfoID);
    }

}